// Stolen from AngularJS as they don't publish this :-(
// https://github.com/angular/angular.js/blob/master/src/ngScenario/browserTrigger.js
'use strict';

(function() {
    var msie = parseInt((/msie (\d+)/.exec(navigator.userAgent.toLowerCase()) || [])[1], 10);

    function indexOf(array, obj) {
        if (array.indexOf) return array.indexOf(obj);

        for ( var i = 0; i < array.length; i++) {
            if (obj === array[i]) return i;
        }
        return -1;
    }



    /**
     * Triggers a browser event. Attempts to choose the right event if one is
     * not specified.
     *
     * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
     * @param {string} eventType Optional event type
     * @param {Object=} eventData An optional object which contains additional event data (such as x,y
     * coordinates, keys, etc...) that are passed into the event when triggered
     */
    window.browserTrigger = function browserTrigger(element, eventType, eventData) {
        if (element && !element.nodeName) element = element[0];
        if (!element) return;

        eventData = eventData || {};
        var keys = eventData.keys;
        var x = eventData.x;
        var y = eventData.y;

        var inputType = (element.type) ? element.type.toLowerCase() : null,
            nodeName = element.nodeName.toLowerCase();

        if (!eventType) {
            eventType = {
                'text':            'change',
                'textarea':        'change',
                'hidden':          'change',
                'password':        'change',
                'button':          'click',
                'submit':          'click',
                'reset':           'click',
                'image':           'click',
                'checkbox':        'click',
                'radio':           'click',
                'select-one':      'change',
                'select-multiple': 'change',
                '_default_':       'click'
            }[inputType || '_default_'];
        }

        if (nodeName == 'option') {
            element.parentNode.value = element.value;
            element = element.parentNode;
            eventType = 'change';
        }

        keys = keys || [];
        function pressed(key) {
            return indexOf(keys, key) !== -1;
        }

        if (msie < 9) {
            if (inputType == 'radio' || inputType == 'checkbox') {
                element.checked = !element.checked;
            }

            // WTF!!! Error: Unspecified error.
            // Don't know why, but some elements when detached seem to be in inconsistent state and
            // calling .fireEvent() on them will result in very unhelpful error (Error: Unspecified error)
            // forcing the browser to compute the element position (by reading its CSS)
            // puts the element in consistent state.
            element.style.posLeft;

            // TODO(vojta): create event objects with pressed keys to get it working on IE<9
            var ret = element.fireEvent('on' + eventType);
            if (inputType == 'submit') {
                while(element) {
                    if (element.nodeName.toLowerCase() == 'form') {
                        element.fireEvent('onsubmit');
                        break;
                    }
                    element = element.parentNode;
                }
            }
            return ret;
        } else {
            var evnt;
            if(/transitionend/.test(eventType)) {
                if(window.WebKitTransitionEvent) {
                    evnt = new WebKitTransitionEvent(eventType, eventData);
                    evnt.initEvent(eventType, false, true);
                }
                else {
                    try {
                        evnt = new TransitionEvent(eventType, eventData);
                    }
                    catch(e) {
                        evnt = document.createEvent('TransitionEvent');
                        evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
                    }
                }
            }
            else if(/animationend/.test(eventType)) {
                if(window.WebKitAnimationEvent) {
                    evnt = new WebKitAnimationEvent(eventType, eventData);
                    evnt.initEvent(eventType, false, true);
                }
                else {
                    try {
                        evnt = new AnimationEvent(eventType, eventData);
                    }
                    catch(e) {
                        evnt = document.createEvent('AnimationEvent');
                        evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
                    }
                }
            }
            else {
                evnt = document.createEvent('MouseEvents');
                x = x || 0;
                y = y || 0;
                evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
                    pressed('alt'), pressed('shift'), pressed('meta'), 0, element);
            }

            /* we're unable to change the timeStamp value directly so this
             * is only here to allow for testing where the timeStamp value is
             * read */
            evnt.$manualTimeStamp = eventData.timeStamp;

            if(!evnt) return;

            var originalPreventDefault = evnt.preventDefault,
                appWindow = element.ownerDocument.defaultView,
                fakeProcessDefault = true,
                finalProcessDefault,
                angular = appWindow.angular || {};

            // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
            angular['ff-684208-preventDefault'] = false;
            evnt.preventDefault = function() {
                fakeProcessDefault = false;
                return originalPreventDefault.apply(evnt, arguments);
            };

            element.dispatchEvent(evnt);
            finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);

            delete angular['ff-684208-preventDefault'];

            return finalProcessDefault;
        }
    };
}());